package com.yunfei.commonbase.hdutil;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.*;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

public class FTPUtil {

    private static final Logger logger = Logger.getLogger(FTPUtil.class.toString());


    /**
     * pom.xml


     <dependency>
        <groupId>commons-net</groupId>
        <artifactId>commons-net</artifactId>
        <version>3.2</version>
     </dependency>
     <dependency>
        <groupId>com.jcraft</groupId>
        <artifactId>jsch</artifactId>
        <version>0.1.55</version>
     </dependency>
     */




    /**
     * 获取FTPClient对象
     *
     * @param ftpHost  服务器IP
     * @param ftpPort  服务器端口号
     * @param username 用户名
     * @param password 密码
     * @return FTPClient
     */
    public static FTPClient getFtpClient(String ftpHost, int ftpPort, String username, String password) throws Exception {
        FTPClient ftp;
        try {
            ftp = new FTPClient();
            // 连接FPT服务器,设置IP及端口
            ftp.connect(ftpHost, ftpPort);
            // 设置用户名和密码
            ftp.login(username, password);
            // 设置连接超时时间,50000毫秒
            ftp.setConnectTimeout(50000);
            // 设置中文编码集，防止中文乱码
            ftp.setControlEncoding("UTF-8");
            if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
                ftp.disconnect();
                throw new Exception("未连接到FTP，用户名或密码错误");
            }
        } catch (SocketException e) {
            e.printStackTrace();
            throw new Exception("FTP的IP地址可能错误，请正确配置");
        } catch (IOException e) {
            e.printStackTrace();
            throw new Exception("FTP的端口错误,请正确配置");
        }
        return ftp;
    }

    /**
     * 关闭FTP方法
     *
     * @param ftp
     * @return
     */
    public static void closeFtpClient(FTPClient ftp) throws Exception {
        try {
            ftp.logout();
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("FTP关闭失败");
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                    logger.info("FTP关闭失败");
                }
            }
        }
    }


    /**
     * 下载FTP下指定文件
     *
     * @param ftpHost  主机IP
     * @param ftpPort  端口
     * @param username ftp用户
     * @param password ftp密码
     * @param ftpPath  ftp路径
     * @param fileName 下载的文件名
     * @throws Exception
     */
    public static void downLoad(String ftpHost, int ftpPort, String username, String password, OutputStream os, String ftpPath, String fileName) throws Exception {
        FTPClient ftp = getFtpClient(ftpHost, ftpPort, username, password);
        try {
            // 跳转到文件目录
            ftp.changeWorkingDirectory(ftpPath);
            // 获取目录下文件集合
            ftp.enterLocalPassiveMode();
            //设置二进制传输，使用BINARY_FILE_TYPE，ASC容易造成文件损坏
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);

            FTPFile[] files = ftp.listFiles();
            for (FTPFile file : files) {
                // 取得指定文件并下载
                if (file.getName().equals(fileName)) {
//                    File downFile = new File(downPath + File.separator + file.getName());
//                    OutputStream out = new FileOutputStream(downFile);
                    // 绑定输出流下载文件,需要设置编码集，不然可能出现文件为空的情况
                    boolean flag = ftp.retrieveFile(new String(file.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1), os);
                    // 下载成功删除文件,看项目需求
                    // ftp.deleteFile(new String(fileName.getBytes("UTF-8"),"ISO-8859-1"));
                    os.flush();
                    os.close();
                    if (!flag) {
                        throw new Exception("下载ftp文件失败");
                    }
                    logger.info("下载ftp文件成功");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("下载ftp文件失败:" + e.getMessage());
        } finally {
            closeFtpClient(ftp);
        }
    }


    public static void main(String[] args) throws Exception
    {
//        FTPClient ftpClient = new FTPClient();//import org.apache.commons.net.ftp.FTPClient;
//        ftpClient.connect("192.168.1.118", 21);//连接ftp
//        ftpClient.login("ftp", "wumeng");//登陆ftp
//        boolean b = ftpClient.changeWorkingDirectory("/jsp/yf5");//需要把文件上传到FTP哪个目录
        File file = new File("D:\\aa.txt");//需要上传的文件
//        System.out.println(ftpClient.storeFile(file.getName(), new FileInputStream(file)));//存储文件,成功返回true,失败false
        upload("192.168.1.118",21,"ftp","wumeng","/jsp/yf9",file.getName(),new FileInputStream(file));


    }


    public static void uploadFile(String ftpHost, int ftpPort, String username, String password,String ftpPath,String filename,InputStream is) throws Exception {
        FTPClient ftp = getFtpClient(ftpHost, ftpPort, username, password);
        ftp.changeWorkingDirectory(ftpPath);
        ftp.storeFile(filename, is);
    }

    /**
     * FTP文件上传工具类
     *
     * @param ftpHost  主机IP
     * @param ftpPort  端口
     * @param username ftp用户
     * @param password ftp密码
     * @param filename 文件名
     * @param ftpPath  ftp路径
     * @throws Exception
     */
    public static void upload(String ftpHost, int ftpPort, String username, String password, String ftpPath, String filename, InputStream is) throws Exception {
        FTPClient ftp = getFtpClient(ftpHost, ftpPort, username, password);
        try {
            // 设置PassiveMode传输
            ftp.enterLocalPassiveMode();
            //设置二进制传输，使用BINARY_FILE_TYPE，ASC容易造成文件损坏
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);

            // 支持中文路径
            String ftpDir = new String(ftpPath.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
            //判断FPT目标文件夹时候存在不存在则创建
            if (!ftp.changeWorkingDirectory(ftpDir)) {
                String[] dirs = ftpDir.split("/");
                String tempPath = "";
                for (String dir : dirs) {

                    if (null == dir || "".equals(dir)) {
                        continue;
                    }
                    tempPath += "/" + dir;
                    if (!ftp.changeWorkingDirectory(tempPath)) {
                        if (!ftp.makeDirectory(tempPath)) {
                            throw new Exception("创建ftp " + tempPath + " 路径失败");
                        }
                        //跳转目标目录
                        ftp.changeWorkingDirectory(tempPath);
                    }
                }
            }

            //上传文件
            String tempName =new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
            boolean flag = ftp.storeFile(tempName, is);
            if (!flag) {
                throw new Exception("上传失败...");
            }
            logger.info("文件 {} 上传成功..."+ftpPath + "/" + filename);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("上传失败...");
        } finally {
            try {
                if (null != is) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            closeFtpClient(ftp);
        }
    }

    /**
     * FPT上文件的复制
     *
     * @param ftp      FTPClient对象
     * @param olePath  原文件地址
     * @param newPath  新保存地址
     * @param fileName 文件名
     * @return
     */
    public boolean copyFile(FTPClient ftp, String olePath, String newPath, String fileName) {
        boolean flag = false;
        try {
            // 跳转到文件目录
            ftp.changeWorkingDirectory(olePath);
            //设置连接模式，不设置会获取为空
            ftp.enterLocalPassiveMode();
            // 获取目录下文件集合
            FTPFile[] files = ftp.listFiles();
            ByteArrayInputStream in = null;
            ByteArrayOutputStream out = null;
            for (FTPFile file : files) {
                // 取得指定文件并下载
                if (file.getName().equals(fileName)) {

                    //读取文件，使用下载文件的方法把文件写入内存,绑定到out流上
                    out = new ByteArrayOutputStream();
                    ftp.retrieveFile(new String(file.getName().getBytes("UTF-8"), "ISO-8859-1"), out);
                    in = new ByteArrayInputStream(out.toByteArray());
                    //创建新目录
                    ftp.makeDirectory(newPath);
                    //文件复制，先读，再写
                    //二进制
                    ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
                    flag = ftp.storeFile(newPath + File.separator + (new String(file.getName().getBytes("UTF-8"), "ISO-8859-1")), in);
                    out.flush();
                    out.close();
                    in.close();
                    if (flag) {
                        logger.info("转存成功");
                    } else {
                        logger.info("复制失败");
                    }


                }
            }
        } catch (Exception e) {
            logger.info("复制失败");
        }
        return flag;
    }

    /**
     * 实现文件的移动，这里做的是一个文件夹下的所有内容移动到新的文件，
     * 如果要做指定文件移动，加个判断判断文件名
     * 如果不需要移动，只是需要文件重命名，可以使用ftp.rename(oleName,newName)
     *
     * @param ftp
     * @param oldPath
     * @param newPath
     * @return
     */
    public boolean moveFile(FTPClient ftp, String oldPath, String newPath) {
        boolean flag = false;

        try {
            ftp.changeWorkingDirectory(oldPath);
            ftp.enterLocalPassiveMode();
            //获取文件数组
            FTPFile[] files = ftp.listFiles();
            //新文件夹不存在则创建
            if (!ftp.changeWorkingDirectory(newPath)) {
                ftp.makeDirectory(newPath);
            }
            //回到原有工作目录
            ftp.changeWorkingDirectory(oldPath);
            for (FTPFile file : files) {

                //转存目录
                flag = ftp.rename(new String(file.getName().getBytes("UTF-8"), "ISO-8859-1"), newPath + File.separator + new String(file.getName().getBytes("UTF-8"), "ISO-8859-1"));
                if (flag) {
                    logger.info(file.getName() + "移动成功");
                } else {
                    logger.info(file.getName() + "移动失败");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("移动文件失败");
        }
        return flag;
    }




    public static void delete(String ftpHost, int ftpPort, String username, String password,String ftpFolder) throws Exception {
        FTPClient ftp = getFtpClient(ftpHost, ftpPort, username, password);
        deleteByFolder(ftp,ftpFolder);
    }
    /**
     * 删除FTP上指定文件夹下文件及其子文件方法，添加了对中文目录的支持
     *
     * @param ftp       FTPClient对象
     * @param FtpFolder 需要删除的文件夹
     * @return
     */
    public static boolean deleteByFolder(FTPClient ftp, String FtpFolder) {
        boolean flag = false;
        try {
            ftp.changeWorkingDirectory(new String(FtpFolder.getBytes("UTF-8"), "ISO-8859-1"));
            ftp.enterLocalPassiveMode();
            FTPFile[] files = ftp.listFiles();
            for (FTPFile file : files) {
                //判断为文件则删除
                if (file.isFile()) {
                    ftp.deleteFile(new String(file.getName().getBytes("UTF-8"), "ISO-8859-1"));
                }
                //判断是文件夹
                if (file.isDirectory()) {
                    String childPath = FtpFolder + File.separator + file.getName();
                    //递归删除子文件夹
                    deleteByFolder(ftp, childPath);
                }
            }
            //循环完成后删除文件夹
            flag = ftp.removeDirectory(new String(FtpFolder.getBytes("UTF-8"), "ISO-8859-1"));
            if (flag) {
                logger.info(FtpFolder + "文件夹删除成功");
            } else {
                logger.info(FtpFolder + "文件夹删除成功");
            }

        } catch (Exception e) {
            e.printStackTrace();
            logger.info("删除失败");
        }
        return flag;

    }


    public static List<String> getFileList(String ftpHost, int ftpPort, String username, String password,String folderPath) throws Exception {
        List<String> fileNameList = new ArrayList<>();
        FTPClient ftp = getFtpClient(ftpHost, ftpPort, username, password);
        readFileByFolder(ftp,folderPath,fileNameList);
        return fileNameList;
    }



    public static boolean readFileByFolder(FTPClient ftp, String folderPath, List<String> fileList) {
        boolean flage = false;
        try {
            ftp.changeWorkingDirectory(new String(folderPath.getBytes("UTF-8"), "ISO-8859-1"));
            //设置FTP连接模式
            ftp.enterLocalPassiveMode();
            //获取指定目录下文件文件对象集合
            FTPFile files[] = ftp.listFiles();
            InputStream in = null;
            BufferedReader reader = null;
            for (FTPFile file : files) {
                //判断为文件夹，递归
                if (file.isDirectory()) {
                    String path = folderPath + "/" + file.getName();
                    readFileByFolder(ftp, path,fileList);
                }else{
                    fileList.add(folderPath+"/"+file.getName());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("文件解析失败");
        }

        return flage;

    }


}
